using System.Collections.Generic;
using System.Text;
using NFreeMarker.Template;

namespace NFreeMarker.Core
{
    /**
     * A template element that contains a nested block
     * that is transformed according to an instance of T
     * TemplateTransformModel
     */

    public sealed class TransformBlock : TemplateElement // NOTE: Was internal
    {
        private readonly Expression _transformExpression;
        private readonly Dictionary<string, Expression> _namedArgs;

        /**
         * Creates new TransformBlock, with a given transformation
         */

        internal TransformBlock(
            Expression transformExpression,
            Dictionary<string, Expression> namedArgs,
            TemplateElement nestedBlock)
        {
            _transformExpression = transformExpression;
            _namedArgs = namedArgs;
            NestedBlock = nestedBlock;
        }

        internal override void Accept(Environment env)
        {
            ITemplateTransformModel ttm = env.GetTransform(_transformExpression);
            if (ttm != null)
            {
                Dictionary<string, ITemplateModel> args;
                if (_namedArgs != null && _namedArgs.Count > 0)
                {
                    args = new Dictionary<string, ITemplateModel>();
                    foreach (KeyValuePair<string, Expression> namedArg in _namedArgs)
                    {
                        string key = namedArg.Key;
                        Expression valueExp = namedArg.Value;
                        ITemplateModel value = valueExp.GetAsTemplateModel(env);
                        args.Add(key, value);
                    }
                }
                else
                {
                    args = new Dictionary<string, ITemplateModel>();
                }
                env.Visit(NestedBlock, ttm, args);
            }
            else
            {
                ITemplateModel tm = _transformExpression.GetAsTemplateModel(env);
                throw InvalidTypeException(tm, _transformExpression, env, "transform");
            }
        }

        public override string GetCanonicalForm()
        {
            var buf = new StringBuilder("<#transform ");
            buf.Append(_transformExpression);
            if (_namedArgs != null)
            {
                foreach (KeyValuePair<string, Expression> namedArg in _namedArgs)
                {
                    buf.Append(' ');
                    buf.Append(namedArg.Key);
                    buf.Append('=');
                    Expression val = namedArg.Value;
                    buf.Append(val.GetCanonicalForm());
                }
            }
            buf.Append(">");
            if (NestedBlock != null)
            {
                buf.Append(NestedBlock.GetCanonicalForm());
            }
            buf.Append("</#transform>");
            return buf.ToString();
        }

        public override string GetDescription()
        {
            return "transform " + _transformExpression;
        }
    }
}